/**
 * 
 */
package de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.datacreation;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
 * 
 * @author Christoph Teichmann
 * created Jun 2, 2014 9:10:04 PM
 * @version 0.1
 */
public class CreateFeatures
{
	private static final String WORDLANG = "|";
	/**
	 * 
	 */
	private static final String SEPERATOR = "\t";
	/**
	 * 
	 */
	private final Object2DoubleOpenHashMap<String> count = new Object2DoubleOpenHashMap<>();
	/**
	 * 
	 */
	private final Map<String,String> mapping = new HashMap<>();
	/**
	 * @param featGenerators
	 */
	public CreateFeatures(FeatureType[] featGenerators)
	{
		if(featGenerators == null)
		{throw new IllegalStateException("Feature generators can not be null");}
		for(FeatureType ft : featGenerators)
		{
			if(ft == null)
			{throw new IllegalStateException("Feature generators can not be null");}
		}
		this.featGenerators = featGenerators;
	}
	/**
	 * 
	 */
	private final FeatureType[] featGenerators;
	/**
	 * 
	 */
	private final HashMap<String, Object2DoubleOpenHashMap<String>> amounts = new HashMap<>();
	/**
	 * 
	 *
	 * @throws IOException
	 */
	public void addFeatures(BufferedReader br, Tokenizer tok) throws IOException
	{
		tok.readFrom(br);
		while(tok.hasNext())
		{
			tok.setToNext();
			String s = tok.currentWord();
			String lang = tok.currentLanguage();
			String other = s;
			for(FeatureType ft : this.featGenerators)
			{other = ft.process(other);}
			other += WORDLANG+lang;
			this.mapping.put(s + WORDLANG + lang, other);
			boolean first = false;
			Object2DoubleOpenHashMap<String> m = this.amounts.get(other);
			if(m==null)
			{
				first = true;
				m = new Object2DoubleOpenHashMap<>();
				this.amounts.put(other, m);
			}
			count.addTo(other, 1.0);
			for(FeatureType ft : this.featGenerators)
			{
				String q = makeFeatName(ft.getFeatName(s), ft.name());
				double d = m.getDouble(q);
				d = ft.updateWeight(q,first,d);
				m.put(q, d);
			}
		}
	}
	/**
	 * 
	 */
	public void writeOutMapping(BufferedWriter br) throws IOException
	{
		boolean first = true;
		for(Map.Entry<String, String> ent : this.mapping.entrySet())
		{
			if(first)
			{first = false;}
			else
			{br.newLine();}
			br.write(ent.getKey());
			br.write("\t");
			br.write(ent.getValue());
		}
	}
	/**
	 *
	 * @param s
	 * @param ft
	 * @return
	 */
	private String makeFeatName(String s, String type)
	{return s+"."+type;}
	/**
	 * 
	 *
	 * @param bw
	 * @throws IOException
	 */
	public void writeOutFeatures(BufferedWriter bw) throws IOException
	{
		boolean first = true;
		for(String s : this.count.keySet())
		{
			if(first)
			{first = false;}
			else
			{bw.newLine();}
			bw.write(s);
			bw.write(SEPERATOR);
			bw.write(Double.toString(this.count.getDouble(s)));
			Object2DoubleOpenHashMap<String> as = this.amounts.get(s);
			for(String k : as.keySet())
			{
				bw.write(SEPERATOR);
				bw.write(k);
				bw.write(SEPERATOR);
				bw.write(Double.toString(as.getDouble(k)));
			}
		}
		bw.flush();
	}
	/**
	 * 
	 *
	 * @param bw
	 * @throws IOException
	 */
	public void writeOutFeatureLexicon(BufferedWriter bw) throws IOException
	{
		boolean first = true;
		for(FeatureType ft : this.featGenerators)
		{
			for(String s : ft.getFeatureOptions())
			{
				if(first)
				{first = false;}
				else
				{bw.newLine();}
				bw.write(this.makeFeatName(s, ft.name()));
				bw.write(SEPERATOR);
				bw.write(ft.name());
				bw.write(SEPERATOR);
				bw.write(ft.getType());
			}
		}
	}
}